package com.runjian.rundo.iot.agent.common.session.manager;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import com.runjian.rundo.iot.agent.common.session.Session;

import cn.hutool.core.util.ObjectUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;

/**
 * 设备连接会话管理
 *
 * @author LiGang
 */
@Getter
@Setter
@RequiredArgsConstructor
public class BaseSessionManager<T extends Session> implements SessionManager<T> {

    /**
     * 会话
     */
    private final Map<String, T> sessionMap = new ConcurrentHashMap<>();

    /**
     * 网关关联会话
     */
    private final Map<String, T> gatewayIdMap = new ConcurrentHashMap<>();

    /**
     * 会话关联网关
     */
    private final Map<T, List<String>> sessionGatewayIdMap = new ConcurrentHashMap<>();

    @Override
    public T get(String id) {
        return sessionMap.get(id);
    }

    @Override
    public T getGatewaySession(String gatewayId) {
        return gatewayIdMap.get(gatewayId);
    }

    @Override
    public T remove(String id) {
        T t = sessionMap.remove(id);
        // 获取会话关联的所有网关
        List<String> gateways = sessionGatewayIdMap.remove(t);
        if (ObjectUtil.isNotEmpty(gateways)) {
            for (String gatewayId : gateways) {
                gatewayIdMap.computeIfPresent(gatewayId, (k, v) -> {
                    // 如果是相同网关
                    if (v.equals(t)) {
                        // 移除
                        return null;
                    } else {
                        // 原样返回,不处理
                        return v;
                    }
                });
            }
        }
        return t;
    }

    @Override
    public T removeGatewaySession(String gatewayId) {
        T t = gatewayIdMap.remove(gatewayId);
        if (null != t) {
            sessionGatewayIdMap.computeIfPresent(t, (k, v) -> {
                v.remove(gatewayId);
                return v;
            });
        }
        return t;
    }

    @Override
    public void put(String id, T session, String... gateways) {
        sessionMap.put(id, session);
        putGatewaySession(session, gateways);
    }

    @Override
    public void putGatewaySession(T session, String... gateways) {
        if (ObjectUtil.isNotEmpty(gateways)) {
            for (String gatewayId : gateways) {
                // 获取旧的Session
                T oldSession = gatewayIdMap.get(gatewayId);
                // 直接覆盖
                gatewayIdMap.put(gatewayId, session);
                if (oldSession != null) {
                    // 移除原来所属的Session
                    sessionGatewayIdMap.computeIfPresent(oldSession, (k, v) -> {
                        v.remove(gatewayId);
                        return v;
                    });
                }
                // 当前网关
                List<String> sessionGateways = sessionGatewayIdMap.getOrDefault(session, new ArrayList<>());
                if (!sessionGateways.contains(gatewayId)) {
                    sessionGateways.add(gatewayId);
                }
            }
        }
    }

}
